#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：turbo 
@File    ：authentication.py
@Author  ：赵加响
@Date    ：2023/5/17 13:10 
@Desc    ：
"""
import re

from django.contrib.auth.models import AnonymousUser
from django.http import JsonResponse

from apps.accounts.models import ExternalSystemAPIWhiteList
from apps.rbac.models import RoleMenuOperate, MenuOperate
from bases.codes import CODE_50006_PERMISSION_DENIED, CODE_50004_UNAUTHORIZED
from bases.messages import MSG_50006_PERMISSION_DENIED, MSG_50004_UNAUTHORIZED
from bases.resp_format import fail_format
from turbo.settings import SYSTEM_CONFIG
from utils.middlewares.constants import WHITE_LIST, GREEN_LIGHT, ADMIN_CONF_WHITE_LIST, API_URL_PREFIX


class RequestInterceptionMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.request = None

    def __call__(self, request):
        self.request = request
        if SYSTEM_CONFIG['permission_url_verify']:
            resp = self.check_permissions()
            if resp is not None:
                return JsonResponse(resp)

        response = self.get_response(request)
        return response

    def check_permissions(self):
        user = self.request.user
        path = self.request.path_info

        # 获取白名单，让白名单中的所有URL和当前访问URL匹配
        for url in WHITE_LIST:
            regex = ".*%s" % (url,)
            if re.match(regex, path):
                return None

        # 判断URL是否是绿灯URL（无需鉴权URL）
        if GREEN_LIGHT in path:
            return None

        # 获取后台管理系统白名单，只有超级用户可以访问。哪怕用户角色是管理员也不见得可以访问
        for django_url in ADMIN_CONF_WHITE_LIST:
            regex = ".*%s" % (django_url,)
            if re.match(regex, path):
                if not user.is_superuser:
                    ret_json = fail_format(CODE_50006_PERMISSION_DENIED, {}, MSG_50006_PERMISSION_DENIED)
                    return ret_json

        # 用户未认证校验
        if isinstance(user, AnonymousUser):
            ret_json = fail_format(CODE_50004_UNAUTHORIZED, {}, MSG_50004_UNAUTHORIZED)
            return ret_json

        # 增加外部系统API用户对内部系统接口访问控制
        if user.user_type == 'I':
            api_user_white_list = ExternalSystemAPIWhiteList.objects.filter(user=user,
                                                                            api_method__iexact=self.request.method)
            if api_user_white_list.exists():
                for external_api in api_user_white_list:
                    regex = re.compile(external_api.api_address)
                    if re.match(regex, path):
                        return None
                ret_json = fail_format(CODE_50006_PERMISSION_DENIED, {}, MSG_50006_PERMISSION_DENIED)
                return JsonResponse(ret_json)
            else:
                ret_json = fail_format(CODE_50006_PERMISSION_DENIED, {}, MSG_50006_PERMISSION_DENIED)
                return JsonResponse(ret_json)

        # 判断当前用户角色是否是管理员，管理员可以访问全部前端URL(admin后台除外)，非管理员则只可以访问授权URL
        if not user.is_admin():
            # 非管理员用户
            url_list = path.split(API_URL_PREFIX)
            request_url = url_list[1]
            request_method = self.request.method

            roles = user.roles.all()

            role_menu_operates = RoleMenuOperate.objects.filter(role__in=roles, is_active=True)

            match_flag = False
            for role_menu_operate in role_menu_operates:
                menu_operates = MenuOperate.objects.filter(id=role_menu_operate.menu_operate.id)
                high_level = ['POST', 'PUT', 'DELETE']
                for menu_operate in menu_operates:
                    if menu_operate.url:
                        for sub_url in menu_operate.url.split(','):
                            regex = "%s[0-9]*/{0,1}$" % (sub_url,)
                            if re.match(regex, request_url):
                                # 记录当前URL所属菜单，并将菜单ID存在session中
                                self.request.session['menu_id'] = menu_operates[0].menu.id
                                if menu_operate.method == request_method:
                                    match_flag = True
                                    break
                                elif menu_operate.method in high_level and request_method == 'GET':
                                    # 如果URL匹配，但是请求方法不同，且请求方法是GET，而URL允许的请求方法在high_level中存在，
                                    # 则也允许访问，GET请求权限较低。
                                    match_flag = True
                                    break

            if not match_flag:
                ret_json = fail_format(CODE_50006_PERMISSION_DENIED, {}, MSG_50006_PERMISSION_DENIED)
                return ret_json

        return None
